#include <common.hpp>
#include "zOpenGLParser.hpp"
#include "../Resource/Shader/ShaderSpecify.hpp"

namespace zzz{
bool zzz::zOpenGLParser::Parse( const string &cmd1, int &id )
{
  string cmd=ToLow_copy(cmd1);
  if (cmd=="glenable") id=GLENABLE;
  else if (cmd=="gldisable") id=GLDISABLE;
  else if (cmd=="glclear") id=GLCLEAR;
  else if (cmd=="glmatrixmode") id=GLMATRIXMODE;
  else if (cmd=="glpushmatrix") id=GLPUSHMATRIX;
  else if (cmd=="glpopmatrix") id=GLPOPMATRIX;
  else if (cmd=="glloadidentity") id=GLLOADIDENTITY;
  else if (cmd=="glviewport") id=GLVIEWPORT;
  
  else if (cmd=="gltranslate") id=GLTRANSLATE;
  else if (cmd=="glrotate") id=GLROTATE;
  else if (cmd=="glpolygonmode") id=GLPOLYGONMODE;
  else if (cmd=="gldepthfunc") id=GLDEPTHFUNC;
  else if (cmd=="glcheckerror") id=GLCHECKERROR;
  else if (cmd=="glcleardepth") id=GLCLEARDEPTH;
  else if (cmd=="glclearcolor") id=GLCLEARCOLOR;
  
  else if (cmd=="glbegin") id=GLBEGIN;
  else if (cmd=="glend") id=GLEND;
  else if (cmd=="glvertex") id=GLVERTEX;
  else if (cmd=="glcolor") id=GLCOLOR;
  else if (cmd=="glnormal") id=GLNORMAL;
  else if (cmd=="gltexcoord") id=GLTEXCOORD;

  else if (cmd=="placeobj") id=PLACEOBJ;
  else if (cmd=="placeenv") id=PLACEENV;
  else if (cmd=="gldrawbuffer") id=GLDRAWBUFFER;

  else if (cmd=="drawcoordinate") id=DRAWCOORDINATE;
  else if (cmd=="drawtriangle") id=DRAWTRIANGLE;
  else if (cmd=="drawtexture") id=DRAWTEXTURE;

  else return false;
  return true;

}

bool zzz::zOpenGLParser::Do( int id, const vector<zParam*> &params, zParam *ret )
{
  double *d0,*d1,*d2,*d3;
  int i0,i1,i2,i3;
  switch(id)
  {
  case GLENABLE:
    if (params.size()!=1) return false;
    d0=zparam_cast<double*>(params[0]);
    i0=(int)(*d0);
    glEnable(i0);
    break;
  case GLDISABLE:
    if (params.size()!=1) return false;
    d0=zparam_cast<double*>(params[0]);
    i0=(int)(*d0);
    glDisable(i0);
    break;
  case GLCLEAR:
    if (params.size()==0)
    {
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }
    else
    {
      int x=0;
      for (zuint i=0;i<params.size();i++)
      {
        d0=zparam_cast<double*>(params[i]);
        i0=(int)(*d0);
        x=x|i0;
      }
      glClear(x);
    }
    break;
  case GLMATRIXMODE:
    if (params.size()!=1) return false;
    d0=zparam_cast<double*>(params[0]);
    i0=(int)(*d0);
    glMatrixMode(i0);
    break;
  case GLPUSHMATRIX:
    if (!params.empty()) return false;
    glPushMatrix();
    break;
  case GLPOPMATRIX:
    if (!params.empty()) return false;
    glPopMatrix();
    break;
  case GLLOADIDENTITY:
    if (!params.empty()) return false;
    glLoadIdentity();
    break;
  case GLVIEWPORT:
    if (params.size()!=4) return false;
    d0=zparam_cast<double*>(params[0]);
    i0=(int)(*d0);
    d1=zparam_cast<double*>(params[1]);
    i1=(int)(*d1);
    d2=zparam_cast<double*>(params[2]);
    i2=(int)(*d2);
    d3=zparam_cast<double*>(params[3]);
    i3=(int)(*d3);
    glViewport(i0,i1,i2,i3);
    break;
  case GLTRANSLATE:
    if (params.size()!=3) return false;
    d0=zparam_cast<double*>(params[0]);
    d1=zparam_cast<double*>(params[1]);
    d2=zparam_cast<double*>(params[2]);
    glTranslated(*d0,*d1,*d2);
    break;
  case GLROTATE:
    if (params.size()!=4) return false;
    d0=zparam_cast<double*>(params[0]);
    d1=zparam_cast<double*>(params[1]);
    d2=zparam_cast<double*>(params[2]);
    d3=zparam_cast<double*>(params[3]);
    glRotated(*d0,*d1,*d2,*d3);
    break;
  case GLPOLYGONMODE:
    if (params.size()!=2) return false;
    d0=zparam_cast<double*>(params[0]);
    i0=(int)(*d0);
    d1=zparam_cast<double*>(params[1]);
    i1=(int)(*d1);
    glPolygonMode(i0,i1);
    break;
  case GLDEPTHFUNC:
    if (params.size()!=1) return false;
    d0=zparam_cast<double*>(params[0]);
    i0=(int)(*d0);
    glDepthFunc(i0);
    break;
  case GLCHECKERROR:
    if (params.size()>1) return false;
    {
      if (!params.empty())
      {
        d0=zparam_cast<double*>(params[0]);
        i0=(int)(*d0);
      }
      cerr<<"CHECK OPENGL ERROR:";
      GLenum glErr = glGetError();
      if (glErr==GL_NO_ERROR)
        if (!params.empty())
          cerr<<"CHECK OPENGL ERROR "<<i0<<": NO ERROR\n";
        else
          cerr<<"CHECK OPENGL ERROR : NO ERROR\n";
      else
        if (!params.empty())
          cerr<<"CHECK OPENGL ERROR :"<<i0<<"\n";
        else 
          cerr<<"CHECK OPENGL ERROR :\n";
      while (glErr != GL_NO_ERROR)
      {
        cerr << "GL Error #" << glErr << "(" ;
        const GLubyte *x=gluErrorString(glErr);
        if ( x != NULL) cerr<< x;
        cerr << ")\n";
        glErr = glGetError();
      }
    }
    break;
  case GLCLEARDEPTH:
    if (params.size()!=1) return false;
    d0=zparam_cast<double*>(params[0]);
    glClearDepth(*d0);
    break;
  case GLCLEARCOLOR:
    if (params.size()!=4) return false;
    d0=zparam_cast<double*>(params[0]);
    d1=zparam_cast<double*>(params[1]);
    d2=zparam_cast<double*>(params[2]);
    d3=zparam_cast<double*>(params[3]);
    glClearColor(*d0,*d1,*d2,*d3);
    break;
  case GLBEGIN:
    if (params.size()!=1) return false;
    d0=zparam_cast<double*>(params[0]);
    i0=(int)(*d0);
    glBegin(i0);
    break;
  case GLEND:
    if (!params.empty()) return false;
    glEnd();
    break;
  case GLCOLOR:
    if (params.size()==3)
    {
      d0=zparam_cast<double*>(params[0]);
      d1=zparam_cast<double*>(params[1]);
      d2=zparam_cast<double*>(params[2]);
      glColor3d(*d0,*d1,*d2);
    }
    else if (params.size()==4)
    {
      d0=zparam_cast<double*>(params[0]);
      d1=zparam_cast<double*>(params[1]);
      d2=zparam_cast<double*>(params[2]);
      d3=zparam_cast<double*>(params[3]);
      glColor4d(*d0,*d1,*d2,*d3);
    }
    else return false;
    break;
  case GLVERTEX:
    if (params.size()==2)
    {
      d0=zparam_cast<double*>(params[0]);
      d1=zparam_cast<double*>(params[1]);
      glVertex2d(*d0,*d1);
    }
    else if (params.size()==3)
    {
      d0=zparam_cast<double*>(params[0]);
      d1=zparam_cast<double*>(params[1]);
      d2=zparam_cast<double*>(params[2]);
      glVertex3d(*d0,*d1,*d2);
    }
    else if (params.size()==4)
    {
      d0=zparam_cast<double*>(params[0]);
      d1=zparam_cast<double*>(params[1]);
      d2=zparam_cast<double*>(params[2]);
      d3=zparam_cast<double*>(params[3]);
      glVertex4d(*d0,*d1,*d2,*d3);
    }
    else return false;
    break;
  case GLNORMAL:
    if (params.size()!=3) return false;
    d0=zparam_cast<double*>(params[0]);
    d1=zparam_cast<double*>(params[1]);
    d2=zparam_cast<double*>(params[2]);
    glNormal3d(*d0,*d1,*d2);
    break;
  case GLTEXCOORD:
    if (params.size()==2)
    {
      d0=zparam_cast<double*>(params[0]);
      d1=zparam_cast<double*>(params[1]);
      glTexCoord2d(*d0,*d1);
    }
    else if (params.size()==3)
    {
      d0=zparam_cast<double*>(params[0]);
      d1=zparam_cast<double*>(params[1]);
      d2=zparam_cast<double*>(params[2]);
      glTexCoord3d(*d0,*d1,*d2);
    }
    else if (params.size()==4)
    {
      d0=zparam_cast<double*>(params[0]);
      d1=zparam_cast<double*>(params[1]);
      d2=zparam_cast<double*>(params[2]);
      d3=zparam_cast<double*>(params[3]);
      glTexCoord4d(*d0,*d1,*d2,*d3);
    }
    else return false;
    break;
  case GLDRAWBUFFER:
    if (params.size()!=1) return false;
    d0=zparam_cast<double>(params[0]);
    i0=(int)(*d0);
    glDrawBuffer(i0);
    break;
  case PLACEOBJ:
    glLoadIdentity();
    m_renderer->camera_.ApplyGL();
    m_renderer->m_pCurObjArcBall->ApplyGL();
    break;
  case PLACEENV:
    glLoadIdentity();
    m_renderer->camera_.ApplyGL();
    m_renderer->m_pCurEnvArcBall->ApplyGL();
    break;
  case DRAWCOORDINATE:
    if (params.size()!=1) return false;
    d0=zparam_cast<double>(params[0]);
    ColorShader.Begin();
    glBegin(GL_LINES);
    glColor4d(1.0,0.0,0.0,1.0);glVertex3d(0,0,0);glVertex3d(*d0,0,0);
    glColor4d(0.0,1.0,0.0,1.0);glVertex3d(0,0,0);glVertex3d(0,*d0,0);
    glColor4d(0.0,0.0,1.0,1.0);glVertex3d(0,0,0);glVertex3d(0,0,*d0);
    glEnd();
    ColorShader.End();
    break;
  case DRAWTRIANGLE:
    if (params.size()!=1) return false;
    d0=zparam_cast<double>(params[0]);
    ColorShader.Begin();
    glBegin(GL_TRIANGLES);
    glColor3d(1.0,0.0,0.0);  glVertex3d( 0.0, *d0, 0.0);
    glColor3d(0.0,1.0,0.0);  glVertex3d(-*d0,-*d0, 0.0);
    glColor3d(0.0,0.0,1.0);  glVertex3d( *d0,-*d0, 0.0);
    glEnd();
    ColorShader.End();
    break;
  case DRAWTEXTURE:
    if (params.size()!=1) return false;
    d0=zparam_cast<double>(params[0]);
    TextureShader.Begin();
    TextureShader.SetUniform1i("tex",0);
    glBegin(GL_QUADS);
    glTexCoord2d(0,0); glVertex3d(-*d0,*d0,0);
    glTexCoord2d(0,1); glVertex3d(-*d0,-*d0,0);
    glTexCoord2d(1,1); glVertex3d(*d0,-*d0,0);
    glTexCoord2d(1,0); glVertex3d(*d0,*d0,0);
    glEnd();
    TextureShader.End();
    break;
  default:
    return false;
  }
  return true;
}

void zOpenGLParser::Init( zScript *zs )
{
  zs->SetVariable("GL_DEPTH_BUFFER_BIT",GL_DEPTH_BUFFER_BIT);
  zs->SetVariable("GL_COLOR_BUFFER_BIT",GL_COLOR_BUFFER_BIT);
  zs->SetVariable("GL_STENCIL_BUFFER_BIT",GL_STENCIL_BUFFER_BIT);

  zs->SetVariable("GL_DEPTH_TEST",GL_DEPTH_TEST);

  zs->SetVariable("GL_PROJECTION",GL_PROJECTION);
  zs->SetVariable("GL_MODELVIEW",GL_MODELVIEW);

  zs->SetVariable("GL_TEXTURE0",GL_TEXTURE0);
  zs->SetVariable("GL_TEXTURE1",GL_TEXTURE1);
  zs->SetVariable("GL_TEXTURE2",GL_TEXTURE2);
  zs->SetVariable("GL_TEXTURE3",GL_TEXTURE3);
  zs->SetVariable("GL_TEXTURE4",GL_TEXTURE4);
  zs->SetVariable("GL_TEXTURE5",GL_TEXTURE5);
  zs->SetVariable("GL_TEXTURE6",GL_TEXTURE6);
  zs->SetVariable("GL_TEXTURE7",GL_TEXTURE7);
  zs->SetVariable("GL_TEXTURE8",GL_TEXTURE8);
  zs->SetVariable("GL_TEXTURE9",GL_TEXTURE9);
  zs->SetVariable("GL_TEXTURE10",GL_TEXTURE10);
  zs->SetVariable("GL_TEXTURE11",GL_TEXTURE11);
  zs->SetVariable("GL_TEXTURE12",GL_TEXTURE12);
  zs->SetVariable("GL_TEXTURE13",GL_TEXTURE13);
  zs->SetVariable("GL_TEXTURE14",GL_TEXTURE14);
  zs->SetVariable("GL_TEXTURE15",GL_TEXTURE15);
  zs->SetVariable("GL_TEXTURE16",GL_TEXTURE16);
  zs->SetVariable("GL_TEXTURE17",GL_TEXTURE17);
  zs->SetVariable("GL_TEXTURE18",GL_TEXTURE18);
  zs->SetVariable("GL_TEXTURE19",GL_TEXTURE19);
  zs->SetVariable("GL_TEXTURE20",GL_TEXTURE20);
  zs->SetVariable("GL_TEXTURE21",GL_TEXTURE21);
  zs->SetVariable("GL_TEXTURE22",GL_TEXTURE22);
  zs->SetVariable("GL_TEXTURE23",GL_TEXTURE23);
  zs->SetVariable("GL_TEXTURE24",GL_TEXTURE24);
  zs->SetVariable("GL_TEXTURE25",GL_TEXTURE25);
  zs->SetVariable("GL_TEXTURE26",GL_TEXTURE26);
  zs->SetVariable("GL_TEXTURE27",GL_TEXTURE27);
  zs->SetVariable("GL_TEXTURE28",GL_TEXTURE28);
  zs->SetVariable("GL_TEXTURE29",GL_TEXTURE29);
  zs->SetVariable("GL_TEXTURE30",GL_TEXTURE30);
  zs->SetVariable("GL_TEXTURE31",GL_TEXTURE31);

  zs->SetVariable("GL_LIGHT0",GL_LIGHT0);
  zs->SetVariable("GL_LIGHT1",GL_LIGHT1);
  zs->SetVariable("GL_LIGHT2",GL_LIGHT2);
  zs->SetVariable("GL_LIGHT3",GL_LIGHT3);
  zs->SetVariable("GL_LIGHT4",GL_LIGHT4);
  zs->SetVariable("GL_LIGHT5",GL_LIGHT5);
  zs->SetVariable("GL_LIGHT6",GL_LIGHT6);
  zs->SetVariable("GL_LIGHT7",GL_LIGHT7);
  zs->SetVariable("GL_LIGHTING",GL_LIGHTING);

  zs->SetVariable("GL_MULTISAMPLE",GL_MULTISAMPLE);

  zs->SetVariable("GL_COLOR_ATTACHMENT0_EXT",GL_COLOR_ATTACHMENT0_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT1_EXT",GL_COLOR_ATTACHMENT1_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT2_EXT",GL_COLOR_ATTACHMENT2_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT3_EXT",GL_COLOR_ATTACHMENT3_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT4_EXT",GL_COLOR_ATTACHMENT4_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT5_EXT",GL_COLOR_ATTACHMENT5_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT6_EXT",GL_COLOR_ATTACHMENT6_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT7_EXT",GL_COLOR_ATTACHMENT7_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT8_EXT",GL_COLOR_ATTACHMENT8_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT9_EXT",GL_COLOR_ATTACHMENT9_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT10_EXT",GL_COLOR_ATTACHMENT10_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT11_EXT",GL_COLOR_ATTACHMENT11_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT12_EXT",GL_COLOR_ATTACHMENT12_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT13_EXT",GL_COLOR_ATTACHMENT13_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT14_EXT",GL_COLOR_ATTACHMENT14_EXT);
  zs->SetVariable("GL_COLOR_ATTACHMENT15_EXT",GL_COLOR_ATTACHMENT15_EXT);
  zs->SetVariable("GL_DEPTH_ATTACHMENT_EXT",GL_DEPTH_ATTACHMENT_EXT);
  zs->SetVariable("GL_STENCIL_ATTACHMENT_EXT",GL_STENCIL_ATTACHMENT_EXT);

  zs->SetVariable("GL_FRONT",GL_FRONT);
  zs->SetVariable("GL_BACK",GL_BACK);
  zs->SetVariable("GL_FRONT_AND_BACK",GL_FRONT_AND_BACK);

  zs->SetVariable("GL_POINT",GL_POINT);
  zs->SetVariable("GL_LINE",GL_LINE);
  zs->SetVariable("GL_FILL",GL_FILL);

  zs->SetVariable("GL_NEVER",GL_NEVER);
  zs->SetVariable("GL_LESS",GL_LESS);
  zs->SetVariable("GL_LEQUAL",GL_LEQUAL);
  zs->SetVariable("GL_EQUAL",GL_EQUAL);
  zs->SetVariable("GL_GREATER",GL_GREATER);
  zs->SetVariable("GL_NOTEQUAL",GL_NOTEQUAL);
  zs->SetVariable("GL_GEQUAL",GL_GEQUAL);
  zs->SetVariable("GL_ALWAYS",GL_ALWAYS);


  zs->SetVariable("GL_POINTS",GL_POINTS);
  zs->SetVariable("GL_LINES",GL_LINES);
  zs->SetVariable("GL_LINE_LOOP",GL_LINE_LOOP);
  zs->SetVariable("GL_LINE_STRIP",GL_LINE_STRIP);
  zs->SetVariable("GL_TRIANGLES",GL_TRIANGLES);
  zs->SetVariable("GL_TRIANGLE_STRIP",GL_TRIANGLE_STRIP);
  zs->SetVariable("GL_TRIANGLE_FAN",GL_TRIANGLE_FAN);
  zs->SetVariable("GL_QUADS",GL_QUADS);
  zs->SetVariable("GL_QUAD_STRIP",GL_QUAD_STRIP);
  zs->SetVariable("GL_POLYGON",GL_POLYGON);
}

void zOpenGLParser::SetRenderer( ArcBallRenderer *renderer )
{
  m_renderer=renderer;
}
}